/* eslint-disable quotes, no-var */
/* disabling quotes makes it easier to copy tests into the example app */
chai.should();

describe('schema-form.provider.js', function() {
  beforeEach(module('schemaForm'));
  describe('defaults()', function() {
    it('should generate default form def from a schema', function() {
      inject(function(schemaForm) {
        var schema = {
          "type": "object",
          "properties": {
            "name": {
              "title": "Name",
              "description": "Gimme yea name lad",
              "type": "string",
            },
            "gender": {
              "title": "Choose",
              "type": "string",
              "enum": [
                "undefined",
                "null",
                "NaN",
              ],
            },
            "overEighteen": {
              "title": "Are you over 18 years old?",
              "type": "boolean",
              "default": false,
            },
            "attributes": {
              "type": "object",
              "required": [ 'eyecolor' ],
              "properties": {
                "eyecolor": { "type": "string", "title": "Eye color" },
                "haircolor": { "type": "string", "title": "Hair color" },
                "shoulders": {
                  "type": "object",
                  "title": "Shoulders",
                  "properties": {
                    "left": { "type": "string" },
                    "right": { "type": "string" },
                  },
                },
              },
            },
          },
        };

        var form = [
          {
            "title": "Name",
            "description": "Gimme yea name lad",
            "schema": {
              "title": "Name",
              "description": "Gimme yea name lad",
              "type": "string",
            },
            "ngModelOptions": {},
            "key": [
              "name",
            ],
            "type": "text",
          },
          {
            "title": "Choose",
            "schema": {
              "title": "Choose",
              "type": "string",
              "enum": [
                "undefined",
                "null",
                "NaN",
              ],
            },
            "ngModelOptions": {},
            "key": [
              "gender",
            ],
            "type": "select",
            "titleMap": [
              {
                "name": "undefined",
                "value": "undefined",
              },
              {
                "name": "null",
                "value": "null",
              },
              {
                "name": "NaN",
                "value": "NaN",
              },
            ],
          },
          {
            "title": "Are you over 18 years old?",
            "schema": {
              "title": "Are you over 18 years old?",
              "type": "boolean",
              "default": false,
            },
            "ngModelOptions": {},
            "key": [
              "overEighteen",
            ],
            "type": "checkbox",
          },
          {
            "title": "attributes",
            "schema": {
              "type": "object",
              "required": [
                "eyecolor",
              ],
              "properties": {
                "eyecolor": {
                  "type": "string",
                  "title": "Eye color",
                },
                "haircolor": {
                  "type": "string",
                  "title": "Hair color",
                },
                "shoulders": {
                  "type": "object",
                  "title": "Shoulders",
                  "properties": {
                    "left": {
                      "type": "string",
                    },
                    "right": {
                      "type": "string",
                    },
                  },
                },
              },
            },
            "ngModelOptions": {},
            "key": [
              "attributes",
            ],
            "type": "fieldset",
            "items": [
              {
                "title": "Eye color",
                "required": true,
                "schema": {
                  "type": "string",
                  "title": "Eye color",
                },
                "ngModelOptions": {},
                "key": [
                  "attributes",
                  "eyecolor",
                ],
                "type": "text",
              },
              {
                "title": "Hair color",
                "schema": {
                  "type": "string",
                  "title": "Hair color",
                },
                "ngModelOptions": {},
                "key": [
                  "attributes",
                  "haircolor",
                ],
                "type": "text",
              },
              {
                "title": "Shoulders",
                "schema": {
                  "type": "object",
                  "title": "Shoulders",
                  "properties": {
                    "left": {
                      "type": "string",
                    },
                    "right": {
                      "type": "string",
                    },
                  },
                },
                "ngModelOptions": {},
                "key": [
                  "attributes",
                  "shoulders",
                ],
                "type": "fieldset",
                "items": [
                  {
                    "title": "left",
                    "schema": {
                      "type": "string",
                    },
                    "ngModelOptions": {},
                    "key": [
                      "attributes",
                      "shoulders",
                      "left",
                    ],
                    "type": "text",
                  },
                  {
                    "title": "right",
                    "schema": {
                      "type": "string",
                    },
                    "ngModelOptions": {},
                    "key": [
                      "attributes",
                      "shoulders",
                      "right",
                    ],
                    "type": "text",
                  },
                ],
              },
            ],
          },
        ];

        var f = schemaForm.defaults(schema);
        f.form.should.be.deep.equal(form);
      });
    });

    it('should handle global defaults', function() {
      inject(function(schemaForm) {
        var schema = {
          "type": "object",
          "properties": {
            "name": {
              "title": "Name",
              "description": "Gimme yea name lad",
              "type": "string",
            },
          },
        };

        var form = [
          {
            "title": "Name",
            "description": "Gimme yea name lad",
            "schema": {
              "title": "Name",
              "description": "Gimme yea name lad",
              "type": "string",
            },
            "ngModelOptions": { "updateOn": "blur" },
            "foo": "bar",
            "key": [
              "name",
            ],
            "type": "text",
          },
        ];

        var f = schemaForm.defaults(schema, schemaForm.typeDefault, {}, { formDefaults: { foo: "bar", ngModelOptions: { updateOn: 'blur' }}});
        f.form.should.be.deep.equal(form);
      });
    });

    it('should handle x-schema-form defaults', function() {
      inject(function(schemaForm) {
        var schema = {
          "type": "object",
          "properties": {
            "name": {
              "title": "Name",
              "description": "Gimme yea name lad",
              "type": "string",
              "x-schema-form": {
                "type": "textarea",
              },
            },
          },
        };

        var f = schemaForm.defaults(schema, schemaForm.typeDefault, {});
        f.form[0].type.should.be.eq('textarea');
      });
    });

    it('should ignore parts of schema in ignore list', function() {
      inject(function(schemaForm) {
        var schema = {
          "type": "object",
          "properties": {
            "name": {
              "title": "Name",
              "description": "Gimme yea name lad",
              "type": "string",
            },
            "gender": {
              "title": "Choose",
              "type": "string",
              "enum": [
                "undefined",
                "null",
                "NaN",
              ],
            },
          },
        };

        // no form is implicitly [ '*' ]
        var defaults = schemaForm.defaults(schema).form;
        schemaForm.merge(schema, [ "*" ], undefined, { gender: true }).should.be.deep.equal([ defaults[0] ]);
      });
    });
  });

  describe('appendRule() and prependRule()', function() {
    beforeEach(module('schemaForm'));
    beforeEach(
      module(function($sceProvider) {
        $sceProvider.enabled(false);
      })
    );

    it('should extend with new defaults', function() {
      module(function(schemaFormProvider) {
        schemaFormProvider.prependRule('string', function(name, schema, options) {
          if (schema.format === 'foobar') {
            var f = schemaFormProvider.createStandardForm(name, schema, options);
            f.type = 'foobar';
            return f;
          }
        });

        schemaFormProvider.appendRule('string', function(name, schema, options) {
          var f = schemaFormProvider.createStandardForm(name, schema, options);
          f.type = 'notused';
          return f;
        });
      });

      inject(function(schemaForm) {
        var schema = {
          "type": "object",
          "properties": {
            "name": {
              "title": "Name",
              "format": "foobar",
              "description": "Gimme yea name lad",
              "type": "string",
            },
            "gender": {
              "title": "Choose",
              "type": "string",
              "enum": [
                "undefined",
                "null",
                "NaN",
              ],
            },
          },
        };

        // no form is implicitly [ '*' ]
        var defaults = schemaForm.defaults(schema).form;
        defaults[0].type.should.be.equal('foobar');
        defaults[0].title.should.be.equal('Name');
        defaults[1].type.should.be.equal('select');
        defaults[1].title.should.be.equal('Choose');
      });
    });
  });

  describe('postProcess()', function() {
    it('should enable post-processing of forms', function() {
      module(function(schemaFormProvider) {
        schemaFormProvider.postProcess(function(form) {
          form.postProcess = true;
          form.length.should.be.eq(1);
          form[0].title.should.be.eq('Name');
          return form;
        });
      });

      inject(function(schemaForm) {
        var schema = {
          "type": "object",
          "properties": {
            "name": {
              "title": "Name",
              "format": "foobar",
              "description": "Gimme yea name lad",
              "type": "string",
            },
          },
        };

        var form = schemaForm.merge(schema, [ "name" ]);
        form.postProcess.should.be.true;
      });
    });
  });

  describe('merge()', function() {
    it('should merge schema and form def', function() {
      inject(function(schemaForm) {
        var schema = {
          "type": "object",
          "properties": {
            "name": {
              "title": "Name",
              "description": "Gimme yea name lad",
              "type": "string",
            },
            "gender": {
              "title": "Choose",
              "type": "string",
              "enum": [
                "undefined",
                "null",
                "NaN",
              ],
            },
          },
        };

        // no form is implicitly [ '*' ]
        var defaults = schemaForm.defaults(schema).form;
        schemaForm.merge(schema).should.be.deep.equal(defaults);
        schemaForm.merge(schema, [ '*' ]).should.be.deep.equal(defaults);
        schemaForm.merge(schema, [ '*', { type: 'fieldset' }]).should.be.deep.equal(defaults.concat([{ type: 'fieldset' }]));

        // simple form
        schemaForm.merge(schema, [ 'gender' ]).should.be.deep.equal([ defaults[1] ]);
        schemaForm.merge(schema, [ 'gender', 'name' ]).should.be.deep.equal([ defaults[1], defaults[0] ]);

        // change it up
        var f = angular.copy(defaults[0]);
        f.title = 'Foobar';
        f.type = 'password';
        schemaForm.merge(schema, [{ key: 'name', title: 'Foobar', type: 'password' }]).should.be.deep.equal([ f ]);
      });
    });

    it('should translate "readOnly" in schema to "readonly" on the merged form defintion', function() {
      inject(function(schemaForm) {
        var schema = {
          "type": "object",
          "properties": {
            "name": {
              "title": "Name",
              "description": "Gimme yea name lad",
              "type": "string",
            },
            "gender": {
              "readOnly": true,
              "title": "Choose",
              "type": "string",
              "enum": [
                "undefined",
                "null",
                "NaN",
              ],
            },
          },
        };

        var merged = schemaForm.merge(schema, [ 'gender' ]);
        merged[0].should.have.property('readonly');
        merged[0].readonly.should.eq(true);
      });
    });

    it('should push readOnly in schema down into objects and arrays', function() {
      inject(function(schemaForm) {
        var schema = {
          'type': 'object',
          'readOnly': true,
          'properties': {
            'sub': {
              'type': 'object',
              'properties': {
                'array': {
                  'type': 'array',
                  'items': {
                    'type': 'object',
                    'properties': {
                      'foo': {
                        'type': 'string',
                      },
                    },
                  },
                },
              },
            },
          },
        };

        var merged = schemaForm.merge(schema, [ '*' ]);

        // sub
        merged[0].should.have.property('readonly');
        merged[0].readonly.should.eq(true);

        // array
        merged[0].items[0].should.have.property('readonly');
        merged[0].items[0].readonly.should.eq(true);

        // array items
        merged[0].items[0].items[0].should.have.property('readonly');
        merged[0].items[0].items[0].readonly.should.eq(true);
      });
    });

    it('should push readonly in form def down into objects and arrays', function() {
      inject(function(schemaForm) {
        var schema = {
          'type': 'object',
          'properties': {
            'sub': {
              'type': 'object',
              'properties': {
                'array': {
                  'type': 'array',
                  'items': {
                    'type': 'object',
                    'properties': {
                      'foo': {
                        'type': 'string',
                      },
                    },
                  },
                },
              },
            },
          },
        };

        var merged = schemaForm.merge(schema, [{ key: 'sub', readonly: true }]);

        // sub
        merged[0].should.have.property('readonly');
        merged[0].readonly.should.eq(true);

        // array
        merged[0].items[0].should.have.property('readonly');
        merged[0].items[0].readonly.should.eq(true);

        // array items
        merged[0].items[0].items[0].should.have.property('readonly');
        merged[0].items[0].items[0].readonly.should.eq(true);
      });
    });

    var arrayObjectSchema = {
      type: "object",
      properties: {
        peopleLivingWithYou: {
          type: "object",
          properties: {
            dependentChildren: {
              type: "array",
              minItems: 1,
              items: {
                type: "object",
                properties: {
                  name: {
                    title: "Name",
                    type: "string",
                  },
                  age: {
                    title: "Age",
                    type: "integer",
                  },
                },
                required: [ "name" ],
              },
            },
          },
          required: [ "dependentChildren" ],
        },
      },
      required: [ "peopleLivingWithYou" ],
    };

    it('merge a schema that defines an array of objects with a form inside a section #900', function() {
      inject(function(schemaForm) {
        var formInsideSection = [{
          type: 'section',
          items: [{
            key: 'peopleLivingWithYou.dependentChildren',
            add: "Add Child",
            title: 'Dependent children details',
            validationMessage: 'Complete all required fields for at least one child',
          }],
        }];

        var merged = schemaForm.merge(arrayObjectSchema, formInsideSection);
        var objectPropertyKeys = merged[0].items[0].items[0];
        var nameKey = objectPropertyKeys.items[0].key;
        var ageKey = objectPropertyKeys.items[1].key;

        nameKey.join('.').should.eq("peopleLivingWithYou.dependentChildren..name");
        ageKey.join('.').should.eq("peopleLivingWithYou.dependentChildren..age");
      });
    });

    it('merge a schema that defines an array of objects with a form without a section #900', function() {
      inject(function(schemaForm) {
        var formWithoutSection = [{
          key: 'peopleLivingWithYou.dependentChildren',
          add: "Add Child",
          title: 'Dependent children details',
          validationMessage: 'Complete all required fields for at least one child',
        }];

        var merged = schemaForm.merge(arrayObjectSchema, formWithoutSection);
        var objectPropertyKeys = merged[0].items[0];
        var nameKey = objectPropertyKeys.items[0].key;
        var ageKey = objectPropertyKeys.items[1].key;

        nameKey.join('.').should.eq("peopleLivingWithYou.dependentChildren..name");
        ageKey.join('.').should.eq("peopleLivingWithYou.dependentChildren..age");
      });
    });
  });
});
